﻿/*****************************************************************************
 
 Use of Ext is under the Ext JS license, for more information, 
 please visit http://extjs.com/products/license.php page. 
  
 You should confirm that you have read, understood and accept ethical criteria listed. 
 If not, see <http://www.mvcnext.com/license/>.
  
 Version: 1.0.0.0
 Website: http://www.mvcnext.com/
 
 Copyright (c) Yoganand R. All rights reserved.
 For continued development and updates, visit http://yogsbreath.net
 
 ******************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Reflection;

namespace MVCnExt.Web.UI.Ext
{
    public class ExtFunction : ExtControl
    {
        private List<ExtComponent> _components = new List<ExtComponent>();
        private List<ExtItem> _xtypes = new List<ExtItem>();
        private List<ScriptReference> _references = new List<ScriptReference>();

        public override List<ScriptReference> GetScriptReferences()
        {
            _references.AddRange(base.GetScriptReferences());

            return _references;
        }

        public override IList<ScriptDescriptor> GetScriptDescriptors()
        {
            IList<ScriptDescriptor> list = base.GetScriptDescriptors();

            if (list.Count == 0)
                list.Add(new ExtScriptControlDescriptor("Ext.util.Observable", this.ClientID, this.ID));

            ScriptControlDescriptorBase desc = (ScriptControlDescriptorBase)list[0];

            //add components
            if (components.Count != 0)
            {
                // build items list
                StringBuilder itemList = new StringBuilder();

                for (int i = 0; i < components.Count; i++)
                {
                    // add comma between items
                    if (i != 0)
                    {
                        itemList.Append(",");
#if DEBUG
                        itemList.AppendLine("\t\t\t");
#endif
                    }

                    // get the item script
                    IList<ScriptDescriptor> descriptors = components[i].GetScriptDescriptors();

                    // get the items's list of script dependencies
                    List<ScriptReference> references = components[i].GetScriptReferences();

                    //make sure the script dependencies are registered
                    _references.AddRange(references);

                    // write the item's config to the list
                    itemList.Append(((ExtScriptControlDescriptor)descriptors[0]).WriteScript(ScriptType.FunctionNew));
                }

                desc.AddPropertyBase("body", itemList);
            }


            //add components
            if (xtypes.Count != 0)
            {
                // build items list
                StringBuilder itemList = new StringBuilder();

                for (int i = 0; i < xtypes.Count; i++)
                {
                    // add comma between items
                    if (i != 0)
                    {
                        itemList.Append(",");
#if DEBUG
                        itemList.AppendLine("\t\t\t");
#endif
                    }

                    // get the item script
                    IList<ScriptDescriptor> descriptors = xtypes[i].GetScriptDescriptors();

                    // get the items's list of script dependencies
                    List<ScriptReference> references = xtypes[i].GetScriptReferences();

                    //make sure the script dependencies are registered
                    _references.AddRange(references);

                    // write the item's config to the list
                    itemList.Append(((ExtScriptControlDescriptor)descriptors[0]).WriteScript(ScriptType.FunctionNew));
                }

                desc.AddPropertyBase("xtypes", itemList);
            }


            //xtype
            if (xtype != null)
            {
                // items script
                ScriptControlDescriptorBase descriptor = (ScriptControlDescriptorBase)xtype.GetScriptDescriptors()[0];

                // get the items's list of script dependencies
                _references.AddRange(xtype.GetScriptReferences());

                // write config script to properties
                desc.AddPropertyBase("xtype", descriptor.WriteScript(ScriptType.FunctionVar));
            }           

            return list;
        }

        /// <summary>
        /// Instantiate the Body template so we can add child controls
        /// </summary>
        protected override void CreateChildControls()
        {
            //call base method
            base.CreateChildControls();
            this.InstantiateTemplate<ExtComponent>(components);
            this.InstantiateTemplate();
        }

        public virtual void InstantiateTemplate<T>(List<T> items)
        {
            if (items.Count == 0)
                return;

            PropertyInfo info;
            ITemplate template;

            for (int i = 0; i < items.Count; i++)
            {
                info = items[i].GetType().GetProperty("items");

                if (info != null)
                {
                    InstantiateTemplate((List<T>)info.GetValue(items[i], null));
                }

                info = items[i].GetType().GetProperty("html");
                if (info == null)
                    continue;

                template = (ITemplate)info.GetValue(items[i], null);
                if (template != null)
                {
                    Panel Content = new Panel();
                    template.InstantiateIn(Content);
                    if (items[i].GetType().GetProperty("id").GetValue(items[i], null) != null)
                        Content.ID = string.Format("{0}_El", items[i].GetType().GetProperty("id").GetValue(items[i], null));
                    else
                        Content.ID = Guid.NewGuid().ToString();
                    Controls.Add(Content);
                    items[i].GetType().GetProperty("contentEl").SetValue(items[i], Content.ClientID, null);
                }
            }
        }        

        public virtual void InstantiateTemplate()
        {
            if (xtype == null)
                return;

            PropertyInfo info;
            ITemplate template;

            for (int i = 0; i < xtype.items.Count; i++)
            {
                info = xtype.items[i].GetType().GetProperty("items");

                if (info != null)
                {
                    InstantiateTemplate((List<ExtItem>)info.GetValue(xtype.items[i], null));
                }

                info = xtype.items[i].GetType().GetProperty("html");
                if (info == null)
                    continue;

                template = (ITemplate)info.GetValue(xtype.items[i], null);
                if (template != null)
                {
                    Panel Content = new Panel();
                    template.InstantiateIn(Content);
                    if (xtype.items[i].GetType().GetProperty("id").GetValue(xtype.items[i], null) != null)
                        Content.ID = string.Format("{0}_El", xtype.items[i].GetType().GetProperty("id").GetValue(xtype.items[i], null));
                    else
                        Content.ID = Guid.NewGuid().ToString();
                    Controls.Add(Content);
                    xtype.items[i].GetType().GetProperty("contentEl").SetValue(xtype.items[i], Content.ClientID, null);
                }
            }
        }        

        [NotifyParentProperty(true)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public virtual List<ExtComponent> components
        {
            get
            {
                return _components;
            }
        }

        [NotifyParentProperty(true)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public virtual List<ExtItem> xtypes
        {
            get
            {
                return _xtypes;
            }
        }

        [NotifyParentProperty(true)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ExtItem xtype { get; set; }        
    }
}
